/**
 * 视频生成服务模块
 * @module services/videoGenerator
 * @description 该模块用于将图片和文本转换为视频，支持多种动画效果
 */

const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path;
const axios = require('axios');
const fs = require('fs');
const path = require('path');

console.log('🎥 视频生成服务启动中...');
console.log(ffmpegPath);
ffmpeg.setFfmpegPath(ffmpegPath);

/**
 * 动画类型枚举
 * @enum {string}
 * @property {string} FADE - 淡入淡出效果
 * @property {string} ZOOM - 缩放效果
 * @property {string} SLIDE - 滑动效果
 */
const ANIMATION_TYPES = {
    FADE: 'fade',
    ZOOM: 'zoom',
    SLIDE: 'slide'
};

/**
 * 默认配置对象
 * @type {Object}
 * @property {string} outputName - 输出文件名
 * @property {string} tempDir - 临时图片存储目录
 * @property {Array<string>} animations - 支持的动画类型数组
 * @property {Array<Object>} images - 图片配置数组
 */
const defaultConfig = {
    outputName: 'output.mp4',
    tempDir: path.join(__dirname, '..', 'temp_images'),
    animations: [
        'fade',
        'zoom',
        'slide',
    ],
    images: [
        {
            duration: 2,
            path: 'https://example.com/image1.jpg',
            animation: {
                type: 'random',
                duration: 1
            }
        }
    ]
};

/**
 * 将生成的视频发送到指定URL
 * @async
 * @function sendResultToUrl
 * @param {Buffer} buffer - 视频文件缓冲区
 * @param {string} [fileName='output.mp4'] - 文件名
 * @returns {Promise<Object>} - 上传结果
 * @throws {Error} - 上传失败时抛出错误
 */
async function sendResultToUrl(buffer, fileName = 'output.mp4') {
    try {
        const APIURL = 'https://env-00jxgx7alqyz.dev-hz.cloudbasefunction.cn/upload_file';
        const FormData = require('form-data');

        const form = new FormData();
        form.append('file', buffer, fileName);

        const response = await axios.post(APIURL, form, {
            headers: {
                ...form.getHeaders(),
                'Content-Length': form.getLengthSync()
            }
        });

        // 直接返回云端的完整结果
        return response.data;
    } catch (error) {
        console.error('发送失败:', error.message);
        return { code: 500, message: error.message };
    }
}

/**
 * 下载图片到本地临时目录
 * @async
 * @function downloadImages
 * @param {Object} config - 配置对象
 * @returns {Promise<Array<string>>} - 下载后的图片路径数组
 * @throws {Error} - 图片下载失败时抛出错误
 */
async function downloadImages(config) {
    // 强制清空并重新创建临时目录
    if (fs.existsSync(config.tempDir)) {
        fs.rmSync(config.tempDir, { recursive: true, force: true });
    }
    fs.mkdirSync(config.tempDir, { recursive: true });
    const imagePaths = [];
    for (let i = 0; i < config.images.length; i++) {
        const imageConfig = config.images[i];
        console.log(imageConfig.path);
        let destPath = '';

        if (imageConfig.path.startsWith('http')) {
            // 下载网络图片（添加错误处理）
            try {
                const response = await axios.get(imageConfig.path, { responseType: 'stream' });
                destPath = path.join(config.tempDir, `image_${i}${path.extname(imageConfig.path) || '.jpg'}`);
                const writer = fs.createWriteStream(destPath);
                response.data.pipe(writer);
                await new Promise((resolve, reject) => {
                    writer.on('finish', resolve);
                    writer.on('error', reject);
                });
            } catch (err) {
                throw new Error(`第 ${i + 1} 张图片下载失败（路径：${imageConfig.path}）\n错误详情：${err.message}`);
            }
        } else {
            // 直接使用本地图片路径
            destPath = path.join(__dirname, imageConfig.path);
            if (!fs.existsSync(destPath)) {
                throw new Error(`本地图片不存在：${destPath}`);
            }
        }

        console.log(`已处理文件：${destPath}`);
        imagePaths.push(destPath);
    }
    return imagePaths;
}

/**
 * 将图片和文字转换为视频
 * @async
 * @function textAndImageToVideo
 * @param {Object} [userConfig={}] - 用户配置对象
 * @param {string} [userConfig.outputName='output.mp4'] - 输出视频文件名
 * @param {string} [userConfig.tempDir='./temp_images'] - 临时图片存储目录
 * @param {Array<string>} [userConfig.animations=['fade', 'zoom', 'slide']] - 支持的动画类型数组
 * @param {Array<Object>} userConfig.images - 图片配置数组
 * @param {string} userConfig.images.path - 图片路径（支持本地路径或URL）
 * @param {number} [userConfig.images.duration=2] - 图片显示时长（秒）
 * @param {Object} [userConfig.images.animation] - 图片动画配置
 * @param {string} [userConfig.images.animation.type='random'] - 动画类型（fade/zoom/slide/random）
 * @param {number} [userConfig.images.animation.duration=1] - 动画时长（秒）
 * @returns {Promise<Object>} - 返回视频生成结果
 * @property {number} code - 状态码（200表示成功）
 * @property {string} message - 返回信息
 * @property {string} [data] - 视频文件URL（成功时返回）
 * @throws {Error} - 当配置错误或视频生成失败时抛出异常
 * @example
 * // 基本用法
 * const result = await textAndImageToVideo({
 *   outputName: 'demo.mp4',
 *   images: [
 *     {
 *       path: 'https://example.com/image1.jpg',
 *       duration: 3,
 *       animation: {
 *         type: 'fade',
 *         duration: 1
 *       }
 *     }
 *   ]
 * });
 */
async function textAndImageToVideo(userConfig = {}) {
    console.log('开始视频生成任务，用户配置:', JSON.stringify(userConfig, null, 2));

    return new Promise(async (resolve, reject) => {
        // 新增：如果传入的是字符串，自动转为JSON对象
        if (typeof userConfig === 'string') {
            try {
                userConfig = JSON.parse(userConfig);
            } catch (err) {
                return reject(new Error('配置参数不是有效的JSON字符串'));
            }
        }
        const config = {
            ...defaultConfig,
            ...userConfig,
            images: userConfig.images || defaultConfig.images
        };

        // console.log(JSON.stringify(config, null, 2));

        const imagePaths = await downloadImages(config);
        console.log("imagePaths", imagePaths);
        const command = ffmpeg();

        // 添加所有输入（现在根据每个配置项的设置）
        config.images.forEach((imageConfig, index) => {
            const isGif = path.extname(imageConfig.path).toLowerCase() === '.gif';
            const input = command.input(imagePaths[index]);

            // 使用每个图片自己的时长配置
            if (!isGif) {
                input.inputOptions([
                    '-loop 1',
                    `-t ${imageConfig.duration || config.duration}`, // 优先使用图片自己的时长
                    '-r 30'
                ]);
            } else {
                input.inputOptions([
                    '-ignore_loop 0',
                    `-t ${imageConfig.duration || config.duration}`, // GIF也使用独立时长
                    '-r 25'
                ]);
            }
        });

        // 在 complexFilter 前添加调试日志
        console.log('滤镜配置:', config.images.map((img, index) => {
            const anim = img.animation || {};
            const animType = anim.type === 'random'
                ? config.animations[Math.floor(Math.random() * config.animations.length)]
                : anim.type;
            return `图片 ${index}: 类型=${animType}, 时长=${anim.duration || 1}`;
        }));

        // 修改滤镜处理部分
        const totalDuration = config.images.reduce((sum, img) => sum + (img.duration || 2), 0);
        command.complexFilter(
            config.images.map((img, index) => {
                const anim = img.animation || {};
                const animDuration = anim.duration || 1;

                // 随机选择动画类型
                const animType = anim.type === 'random'
                    ? config.animations[Math.floor(Math.random() * config.animations.length)]
                    : anim.type;

                // 检查动画类型是否有效
                const isValidAnimation = animType && config.animations.includes(animType);

                console.log(`图片 ${index} 使用的动画类型: ${isValidAnimation ? animType : '无'}`);

                let animFilter = '';
                if (isValidAnimation) {
                    switch (animType) {
                        case 'fade':
                            animFilter = `fade=t=in:st=0:d=${animDuration},`;
                            break;
                        case 'zoom':
                            animFilter = `zoompan=z='1.2-0.2*min(on/${animDuration},1)':d=1:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=${config.width || 1242}x${config.height || 1660},`;
                            break;
                        case 'slide':
                            animFilter = `split[base][org];[base]trim=duration=${animDuration},color=black:${config.width || 1242}x${config.height || 1660}[bg];[bg][org]overlay=x='-w+(w/${animDuration})*t':y=0:enable='between(t,0,${animDuration})',`;
                            break;
                    }
                }

                return [
                    `[${index}:v]scale=1242:1660:force_original_aspect_ratio=decrease[scaled_${index}];`,
                    `[scaled_${index}]pad=1242:1660:(ow-iw)/2:(oh-ih)/2[padded_${index}];`,
                    animFilter ? `[padded_${index}]${animFilter}format=yuv420p[fmt_${index}];` : `[padded_${index}]format=yuv420p[fmt_${index}];`
                ];
            }).flat().join('') +
            `${config.images.map((_, i) => `[fmt_${i}]`).join('')}concat=n=${config.images.length}:v=1:a=0[concat_out];` +
            `[concat_out]fade=t=out:st=${totalDuration - 1}:d=1[fade_out];` +
            `[fade_out]tpad=stop=1:stop_mode=clone[outv]`,
            '[outv]'
        );

        command.on('start', (cmd) => {
            console.log('FFmpeg命令:', cmd);
            console.log('FFmpeg 进程已启动');
        })
        .on('progress', (progress) => {
            // 将时间标记转换为秒数
            const timeParts = progress.timemark.split(':');
            const currentSeconds = (+timeParts[0]) * 3600 + (+timeParts[1]) * 60 + (+timeParts[2]);

            // 计算百分比，并确保不超过 100%
            const percent = Math.min(100, Math.round((currentSeconds / totalDuration) * 100));
            console.log(`处理进度: ${percent}%`);
        })
        .on('end', async () => {
            try {
                console.log('视频生成完成，准备上传');
                const videoBuffer = fs.readFileSync(config.outputName);  // 使用 config.outputName
                const res = await sendResultToUrl(videoBuffer, config.outputName);
                console.log('上传结果:', res);

                // 删除临时文件
                fs.rmSync(config.tempDir, { recursive: true, force: true });
                fs.unlinkSync(config.outputName);  // 使用 config.outputName

                if (res.code === 200) {
                    resolve(res);
                } else {
                    resolve({
                        code: 500,
                        message: "转换失败",
                        data: videoBuffer || null
                    });
                }
            } catch (error) {
                reject(error);
            }
            console.log('FFmpeg 进程已完成，准备清理临时文件');
        })
        .on('error', (err) => {
            console.error('FFmpeg 进程出错:', err.message);
            reject(err);
        })
        .output(config.outputName)  // 使用 config.outputName
        .videoCodec('libx264')
        .outputOptions([
            '-r 30',
            '-pix_fmt yuv420p',
            '-movflags +faststart'
        ])
        .run();
    });
}

module.exports = {
    textAndImageToVideo
}

// 如果直接运行该文件，执行测试用例
if (require.main === module) {
    // 自定义参数（每张显示3秒，输出文件名改为demo.mp4）
    textAndImageToVideo({
        outputName: 'demo.mp4',
        images: [
            {
                duration: 3,
                path: 'https://img-s-msn-com.akamaized.net/tenant/amp/entityid/BB1msMIB.img'
            },
            {
                duration: 6,
                path: 'https://img-s-msn-com.akamaized.net/tenant/amp/entityid/BB1msMIB.img',
                animation: {
                    type: 'fade', // 随机选择动画
                    duration: 3
                }
            }
        ]
    });
}
